/*
    $Id$
    MAR another horizontal scroll action game
    Copyright (C) 2009 Japan Manoretimedia Lab.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed self the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "input.h"
#include "util.h"
#include <dinput.h>
#include <assert.h>

struct Input {
    LPDIRECTINPUT8        di;
    LPDIRECTINPUTDEVICE8  diDevice;
    bool keyStatusArray[KS_NUM];
    bool prevKeyStatusArray[KS_NUM];
};

Input *
IN_Instance(void)
{
    static Input input;

    return &input;
}

HRESULT
IN_Init(Input *self, HINSTANCE inst, HWND hWnd)
{
    HRESULT hr;

    assert(self);

    IFR(DirectInput8Create(inst, DIRECTINPUT_VERSION,
        IID_IDirectInput8, (VOID**)&self->di, NULL));
    assert(self->di);

    IFR(self->di->CreateDevice(GUID_SysKeyboard, &self->diDevice, NULL));
    assert(self->diDevice);

    IFR(self->diDevice->SetDataFormat(&c_dfDIKeyboard));

    IFR(self->diDevice->SetCooperativeLevel(
        hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE));

    return hr;
}

void
IN_Term(Input *self)
{
    assert(self);

    if (self->diDevice) {
        self->diDevice->Unacquire(); 
        self->diDevice->Release();
        self->diDevice = NULL; 
    } 

    SAFE_RELEASE(self->di);
}

#define KEYDOWN(name, key) (name[key] & 0x80) 

HRESULT
IN_FrameMove(Input *self)
{
    HRESULT hr;
    char    buffer[256];

    assert(self);

    if (!self->diDevice) {
        return S_OK;
    }

    hr = self->diDevice->Poll();
    if (FAILED(hr)) {
        hr = self->diDevice->Acquire();
        if (FAILED(hr)) {
            // try next time...
            return S_OK;
        }
    }

    hr = self->diDevice->GetDeviceState(sizeof buffer, (LPVOID)&buffer);
    if (FAILED(hr)) {
        self->diDevice->Unacquire(); 
        MessageBox(NULL, L"GetDeviceState failed", Title(), MB_OK);
        return hr;
    }

    for (int i=0; i<KS_NUM; ++i) {
        self->prevKeyStatusArray[i] = self->keyStatusArray[i];
    }
    memset(self->keyStatusArray, 0, sizeof self->keyStatusArray);

    if (KEYDOWN(buffer, DIK_UP)) {
        self->keyStatusArray[KS_Up] = true;
    } else if (KEYDOWN(buffer, DIK_DOWN)) {
        self->keyStatusArray[KS_Down] = true;
    }

    if (KEYDOWN(buffer, DIK_RIGHT)) {
        self->keyStatusArray[KS_Right] = true;
    } else if (KEYDOWN(buffer, DIK_LEFT)) {
        self->keyStatusArray[KS_Left] = true;
    }

    if (KEYDOWN(buffer, DIK_A)) {
        self->keyStatusArray[KS_A] = true;
    }
    if (KEYDOWN(buffer, DIK_B)) {
        self->keyStatusArray[KS_B] = true;
    }
    if (KEYDOWN(buffer, DIK_SPACE)) {
        self->keyStatusArray[KS_Start] = true;
    }

#if 0
    static int count;

    DebugPrintf(L"%8d U%d D%d L%d R%d A%d B%d S%d\n",
        ++count,
        self->keyStatusArray[KS_Up],
        self->keyStatusArray[KS_Down],
        self->keyStatusArray[KS_Left],
        self->keyStatusArray[KS_Right],
        self->keyStatusArray[KS_A],
        self->keyStatusArray[KS_B],
        self->keyStatusArray[KS_Start]);
#endif /* key debug */

    return hr;
}

bool
IN_IsPressed(Input *self, KeyStatusType t)
{
    assert(self);
    assert(0 <= t && t < KS_NUM);

    return self->keyStatusArray[t];
}

bool
IN_IsPressedTrigger(Input *self, KeyStatusType t)
{
    bool ret;

    assert(self);
    assert(0 <= t && t < KS_NUM);

    ret = (!self->prevKeyStatusArray[t]) && self->keyStatusArray[t];

    if (ret) {
        DebugPrintf(L"PressedTrigger=%d\n", ret);
    }
    return ret;
}

bool
IN_IsReleasedTrigger(Input *self, KeyStatusType t)
{
    bool ret;

    assert(self);
    assert(0 <= t && t < KS_NUM);

    ret = self->prevKeyStatusArray[t] && (!self->keyStatusArray[t]);

    if (ret) {
        DebugPrintf(L"ReleasedTrigger=%d\n", ret);
    }
    return ret;
}
